package com.e.library.http;


import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;

import com.e.library.utils.ESPUtils;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * Created by lxy on 2016/7/10.
 */
public class EClient {

    private EApi eApi;
    private Retrofit retrofit;
    public static String session;
    private static volatile EClient instance;
    private Context mContext;
    public static SparseArray<String> status = new SparseArray<>(34);

    public static EClient with(){
        if (instance == null){
            synchronized (EClient.class){
                if (instance == null){
                    instance = new EClient();
                }
            }
        }

        return instance;
    }

    private EClient(){}

    public void init(Context context){
        Context cxt = context.getApplicationContext();
        this.mContext = cxt;
        HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                if (TextUtils.isEmpty(message)){
                    return;
                }
                /**为了让LOG显示简洁，过滤部分，仅显示URL和JSON*/
//                if (message.contains("--> POST") || message.contains("--> GET")){
//                    Log.i("Response",message);
//                }else if (message.contains("{") && message.contains("}")){
//                    Log.i("Response",message);
//                }
                Log.i("Response",message);

            }
        });
        logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        File file = new File(cxt.getCacheDir(),"cache");
        Cache cache = new Cache(file,1024*1024*10);//10mb

        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(15, TimeUnit.SECONDS)
                .connectTimeout(15,TimeUnit.SECONDS)
                .addInterceptor(new ParamsInterceptor(cxt))
                .addInterceptor(logInterceptor)
                .retryOnConnectionFailure(true)
                .cache(cache)
                .build();


        retrofit = new Retrofit.Builder()
                .baseUrl(EApi.BASE_URL)
                .addConverterFactory(new ResponseFactory(cxt))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
                .validateEagerly(false)
                .client(client)
                .build();
    }

    public <T> T service(Class<T> clz) {
        return retrofit.create(clz);
    }


    public Context app(){
        return mContext;
    }

    public EApi api(){
        if (eApi == null){
            eApi = service(EApi.class);
        }
        return eApi;
    }

    public static class ResponseFactory extends Converter.Factory{
        private Context cxt;

        public ResponseFactory(Context cxt) {
            this.cxt = cxt;
        }

        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            return new ResponseConverter(cxt);
        }
    }

    public static class ResponseConverter implements Converter<ResponseBody,EResponse>{

        private Context cxt;

        public ResponseConverter(Context cxt) {
            this.cxt = cxt;
        }

        @Override
        public EResponse convert(ResponseBody value) throws IOException {
            EResponse response = new EResponse(value.string());
            if (response.expire()){
                throw new SessionExpireException("请重新登录再试！");
            }
            String sid = response.session;
            if (!TextUtils.isEmpty(sid)){
                session = sid;//将session保存下来
                ESPUtils.setString(cxt,"session",session);

            }
            return response;
        }
    }

    /**
     * 公共参数拦截器
     */
    private static class ParamsInterceptor implements Interceptor{

        private Context cxt;

        public ParamsInterceptor(Context cxt) {
            this.cxt = cxt;
        }

        @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {

            /**使用SP解决session过期bug*/
            String sid = ESPUtils.getString(cxt,"session",null);

            Request original = chain.request();
            HttpUrl originalHttpUrl = original.url();
            HttpUrl.Builder newUrlBuilder = originalHttpUrl.newBuilder();
            Request.Builder newRequestBuilder = original.newBuilder();
            if(original.body() instanceof FormBody){
                //post
                FormBody.Builder newFormBody = new FormBody.Builder();
                FormBody oldFormBody = (FormBody) original.body();
                for (int i = 0;i<oldFormBody.size();i++){
                    newFormBody.addEncoded(oldFormBody.encodedName(i),oldFormBody.encodedValue(i));
                }
                //newFormBody.addEncoded("is_app","1");
                if (!TextUtils.isEmpty(sid)){
                    newFormBody.addEncoded("session_id",sid);
                }
                newRequestBuilder.post(newFormBody.build());
            }else {
                //get
                //newUrlBuilder.addQueryParameter("is_app","1");
                if (!TextUtils.isEmpty(sid)){
                    newUrlBuilder.addQueryParameter("session_id",sid);
                }
            }

            HttpUrl url = newUrlBuilder.build();
            return chain.proceed(newRequestBuilder.url(url).build());
        }
    }

    public void post(String url, EObserver observer) {
        post(url,new HashMap<String, String>(0),observer);
    }

    public void post(String url, Map<String, String> params, EObserver observer) {
        Observable<EResponse> observable = api().post(url,params);
        observer(observable,observer);
    }

    public void get(String url, EObserver observer) {
        Observable<EResponse> observable = api().get(url);
        observer(observable,observer);
    }

    public void get(String url, Map<String, String> params, EObserver observer) {
        Observable<EResponse> observable = api().get(url,params);
        observer(observable,observer);
    }

    public void observer(final Observable<EResponse> observable, EObserver observer) {
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);

    }

    public void clearSession(Context context){
        session = null;
        ESPUtils.setString(context,"session",null);
    }

    //状态码
    static {
        status.put(-1,"系统异常，请稍后再试");

        status.put(100000,"该方法需要登录才能进行操作");
        status.put(100001,"非法访问");

        status.put(300001,"上传图片类型不正确");
        status.put(300002,"保存图片失败");
        status.put(300003,"上传图片校验失败");
        status.put(300004,"上传图片大小超过限制");

        status.put(400001,"手机号或密码不能为空");
        status.put(400002,"用户不存在");
        status.put(400003,"手机号或密码错误");
        status.put(400004,"注册失败");
        status.put(400005,"验证码错误");
        status.put(400006,"没有找到该店铺");
        status.put(400007,"消息内容不能为空");
        status.put(400008,"上传图片不能为空");
        status.put(400009,"请退出重新登录再试");
        status.put(400010,"短信接口错误");
        status.put(400011,"没有好友");
        status.put(400012,"你还没登录");
        status.put(400000,"请求出错了，请稍后再试");
        status.put(400013,"请先发送验证码");
        status.put(400014,"用户id或者对象id为空");
        status.put(400015,"找不到匹配结果");
        status.put(400016,"内容不全或数据丢失");
        status.put(400017,"需要操作的内容不为空");
        status.put(400018,"获取用户详细信息错误");

        status.put(100000,"该方法需要登录才能进行操作");
        status.put(100001,"非法访问");
        status.put(400019,"用户已存在");
        status.put(400020,"下载失败，请确保您有足够的金币！");
        status.put(400021,"您今天的下载次数已用光！");
        status.put(400022,"不能关注自己哦，亲爱的！");
        status.put(400023,"获取用户详细信息错误");
        status.put(400024,"已关注该用户");
        status.put(400026,"用户已被禁用");
    }

}
